Force адзін з двух класа пітона атрыбутаў, якія будуць заўсёды быць прысвоена значэнне?

Ці ёсць спосаб у Python такім чынам, што дадзены клас пітона:

class Foo(object):
    apple = None
    orange = None
    def __init__(self, apple=None, orange=None)
        super(Foo, self).__init__()
        self.apple = apple
        self.orange = orange

пасля таго, як аб'ект Foo з'яўляецца <�моцны> INIT , адзін з двух атрыбутаў (яблык, апельсін) заўсёды павінны быць прызначаныя на значэнне, адрознае ад None, і што ў самыя кароткія тэрміны павінны абодва атрыбуту быць прызначаныя на нешта іншае, чым None ,

Іншымі словамі:

                      orange is None    |    orange is not None
                                        |
apple is None              NO           |         YES                                         
________________________________________|___________________________
                                        |
apple is not None          YES          |         NO

Як бы адзін зрабіць гэта ў Python?

1
Вы павінны даць больш падрабязную інфармацыю. Як вы хочаце працаваць? Што вы хочаце, каб адбылося, калі хтосьці праходзіць у значэннях як яблык і апельсін? Калі адзін прызначаецца і хто-то спрабуе прысвоіць іншы, вы хочаце, каб першы адзін павінен быць усталяваны ў None аўтаматычна, ці вы хочаце, узнікае памылка, або што?
дададзена аўтар BrenBarn, крыніца
Вы павінны даць больш падрабязную інфармацыю. Як вы хочаце працаваць? Што вы хочаце, каб адбылося, калі хтосьці праходзіць у значэннях як яблык і апельсін? Калі адзін прызначаецца і хто-то спрабуе прысвоіць іншы, вы хочаце, каб першы адзін павінен быць усталяваны ў None аўтаматычна, ці вы хочаце, узнікае памылка, або што?
дададзена аўтар BrenBarn, крыніца
Вы павінны даць больш падрабязную інфармацыю. Як вы хочаце працаваць? Што вы хочаце, каб адбылося, калі хтосьці праходзіць у значэннях як яблык і апельсін? Калі адзін прызначаецца і хто-то спрабуе прысвоіць іншы, вы хочаце, каб першы адзін павінен быць усталяваны ў None аўтаматычна, ці вы хочаце, узнікае памылка, або што?
дададзена аўтар BrenBarn, крыніца

13 адказы

У канструктару, гэта досыць проста падняць а ValueError , калі яны абодва None або абодва набору. Праблема заключаецца ў далейшым у кодзе.

Кіруючыся прынцыпам найменшага здзіўлення, я думаю, вы павінны пазначыць зменныя метады прыватных і выкарыстанне сетэра (не ўласнасць сетэр, проста старыя метады). Гэта ясна паказвае, што вы робіце дадатковую логіку, калі значэнне ўстаноўлена, і гэта дае відавочнае месца, каб дадаць дадатковую логіку пазней, калі гэта неабходна. Выкарыстанне геттер метадаў уласцівасцяў было б добра, аднак. Дык нешта накшталт гэтага:

class Foo(object):
    def __init__(self, apple=None, orange=None):
        super(Foo, self).__init__()
        if None is apple and None is orange:
            raise ValueError('apple and orange cannot both be None')
        if None is not apple and None is not orange:
            raise ValueError('apple and orange cannot both be set')

        self._apple = apple
        self._orange = orange

    @property
    def apple(self):
        return self._apple

    @property
    def orange(self):
        return self._orange

    def setAppleClearOrange(self, value):
        if (value is None):
            raise ValueError('Cannot set both to None')
        self._orange = None
        self._apple = value

    def setOrangeClearApple(self, value):
        if (value is None):
            raise ValueError('Cannot set both to None')
        self._apple = None
        self._orange = value

Так, гэта крыху шматслоўны, але гэта <�ет> відавочна, , што вашыя намеры, якія на самай справе больш важным.

4
дададзена
проста запоўніць прабелы перад self._apple = яблычнага і першы @property , і ён будзе pastable ў інтэрактыўным рэжыме.
дададзена аўтар Elazar, крыніца
Я думаю, што яблык ня None == аранжавы ня None застаецца чытаным, і карацей.
дададзена аўтар Elazar, крыніца
Я адкаціў рэдагаваць, таму што я назваў метады як форма самастойнай дакументацыі. Я спецыяльна сказаў, чаму я не выкарыстаў сетэр. Выключэння ў метадах набору таксама неабходныя для таго, каб «толькі адзін можа быць None » абмежаванне не не парушаецца.
дададзена аўтар jpmc26, крыніца
@Elazar Там аргумент, для гэтага ў канструктару. Я абраў для асобных праверак, так што я мог бы выкарыстаць самыя падрабязныя паведамленні пра памылкі. Да ОП там.
дададзена аўтар jpmc26, крыніца
@Elazar Дзякуючы кучу. Нейкім чынам выкарыстаў 3 прасторы на першым узроўні водступу на працягу метадаў. Павінна быць выпраўлена. Немагчыма ўставіць у інтэрактыўным рэжыме, але ён павінен працаваць з файла ў цяперашні час.
дададзена аўтар jpmc26, крыніца
@Elazar Падобна, StackOverflow хавае іх. Я спрабаваў паставіць іх, але яны не паказваюць на адказ. Вы можаце дадаць іх, калі вы ведаеце, што-то я раблю не так.
дададзена аўтар jpmc26, крыніца
Вельмі добра. Лакалізуе логіку апрацоўкі толькі неабходныя зменныя +1.
дададзена аўтар jpaugh, крыніца

У канструктару, гэта досыць проста падняць а ValueError , калі яны абодва None або абодва набору. Праблема заключаецца ў далейшым у кодзе.

Кіруючыся прынцыпам найменшага здзіўлення, я думаю, вы павінны пазначыць зменныя метады прыватных і выкарыстанне сетэра (не ўласнасць сетэр, проста старыя метады). Гэта ясна паказвае, што вы робіце дадатковую логіку, калі значэнне ўстаноўлена, і гэта дае відавочнае месца, каб дадаць дадатковую логіку пазней, калі гэта неабходна. Выкарыстанне геттер метадаў уласцівасцяў было б добра, аднак. Дык нешта накшталт гэтага:

class Foo(object):
    def __init__(self, apple=None, orange=None):
        super(Foo, self).__init__()
        if None is apple and None is orange:
            raise ValueError('apple and orange cannot both be None')
        if None is not apple and None is not orange:
            raise ValueError('apple and orange cannot both be set')

        self._apple = apple
        self._orange = orange

    @property
    def apple(self):
        return self._apple

    @property
    def orange(self):
        return self._orange

    def setAppleClearOrange(self, value):
        if (value is None):
            raise ValueError('Cannot set both to None')
        self._orange = None
        self._apple = value

    def setOrangeClearApple(self, value):
        if (value is None):
            raise ValueError('Cannot set both to None')
        self._apple = None
        self._orange = value

Так, гэта крыху шматслоўны, але гэта <�ет> відавочна, , што вашыя намеры, якія на самай справе больш важным.

4
дададзена
проста запоўніць прабелы перад self._apple = яблычнага і першы @property , і ён будзе pastable ў інтэрактыўным рэжыме.
дададзена аўтар Elazar, крыніца
Я думаю, што яблык ня None == аранжавы ня None застаецца чытаным, і карацей.
дададзена аўтар Elazar, крыніца
Я адкаціў рэдагаваць, таму што я назваў метады як форма самастойнай дакументацыі. Я спецыяльна сказаў, чаму я не выкарыстаў сетэр. Выключэння ў метадах набору таксама неабходныя для таго, каб «толькі адзін можа быць None » абмежаванне не не парушаецца.
дададзена аўтар jpmc26, крыніца
@Elazar Там аргумент, для гэтага ў канструктару. Я абраў для асобных праверак, так што я мог бы выкарыстаць самыя падрабязныя паведамленні пра памылкі. Да ОП там.
дададзена аўтар jpmc26, крыніца
@Elazar Дзякуючы кучу. Нейкім чынам выкарыстаў 3 прасторы на першым узроўні водступу на працягу метадаў. Павінна быць выпраўлена. Немагчыма ўставіць у інтэрактыўным рэжыме, але ён павінен працаваць з файла ў цяперашні час.
дададзена аўтар jpmc26, крыніца
@Elazar Падобна, StackOverflow хавае іх. Я спрабаваў паставіць іх, але яны не паказваюць на адказ. Вы можаце дадаць іх, калі вы ведаеце, што-то я раблю не так.
дададзена аўтар jpmc26, крыніца
Вельмі добра. Лакалізуе логіку апрацоўкі толькі неабходныя зменныя +1.
дададзена аўтар jpaugh, крыніца

Нешта накшталт

if !((self.apple==None)^(self.orange==None))
   //some error

Можа зрабіць трук ... ^ аператар XOR, які вяртае ісціну, калі адзін, але не абодва з аперанд з'яўляюцца праўдзівымі.

1
дададзена

Нешта накшталт

if !((self.apple==None)^(self.orange==None))
   //some error

Можа зрабіць трук ... ^ аператар XOR, які вяртае ісціну, калі адзін, але не абодва з аперанд з'яўляюцца праўдзівымі.

1
дададзена

Нешта накшталт

if !((self.apple==None)^(self.orange==None))
   //some error

Можа зрабіць трук ... ^ аператар XOR, які вяртае ісціну, калі адзін, але не абодва з аперанд з'яўляюцца праўдзівымі.

1
дададзена

Here is a version that will set the other aspect to None if necessary. You'll have to define what should happen if they are both set to None

class Foo(object):
    def __init__(self, apple=None, orange=None):
        # make sure exactly 1 of apple/orange is not None
        if sum(x is None for x in (apple, orange)) != 1:
            raise ...
        self._apple = apple
        self._orange = orange

    @property
    def apple(self):
        return self._apple

    @apple.setter
    def apple(self, value):
        if value is not None:
            self._orange = None
        elif self._orange is None:
            raise ...
        self._apple = value

    @property
    def orange(self):
        return self._orange

    @orange.setter
    def orange(self, value):
        if value is not None:
            self._apple = None
        elif self._apple is None:
            raise ...
        self._orange = value
0
дададзена
objs = filter(None, [apple, orange, ...])
if len(objs) == 0:
   raise Exception("At least 1 object of [apple, orange] must be different from None.") 
elif len(objs) > 1:
    raise Exception("At most 1 object of [apple, orange] should be different from None.")
0
дададзена
objs = filter(None, [apple, orange, ...])
if len(objs) == 0:
   raise Exception("At least 1 object of [apple, orange] must be different from None.") 
elif len(objs) > 1:
    raise Exception("At most 1 object of [apple, orange] should be different from None.")
0
дададзена
objs = filter(None, [apple, orange, ...])
if len(objs) == 0:
   raise Exception("At least 1 object of [apple, orange] must be different from None.") 
elif len(objs) > 1:
    raise Exception("At most 1 object of [apple, orange] should be different from None.")
0
дададзена

You could override __setattr__() for that class, and have it handle that logic for you. See http://docs.python.org/2/reference/datamodel.html#object.setattr

Нешта накшталт

class FooBar(object):
    def __setattr__(self, key, val):
        if key == 'apple' or key == 'orange':
            # Decide what to do about it
        self.__dict__[key] = val

Звярніце ўвагу, што вам неабходна атрымаць доступ да ключа праз аб'екта __ дыктуе __ , каб пазбегнуць бясконцага цыклу, так як __ SetAttr __() замяняе нармальны механізм прызначэння.

Акрамя таго, звярніце ўвагу, што гэта будзе правяраць <�моцны> усе прысваенне гэтых двух зменных, у тым ліку і ва ўласным кодзе. Калі гэта не тое, што вы хочаце, а затым паставіць некаторыя выпрабаванні ў __ __ INIT() , як і іншыя прапанавалі.

0
дададзена

You could override __setattr__() for that class, and have it handle that logic for you. See http://docs.python.org/2/reference/datamodel.html#object.setattr

Нешта накшталт

class FooBar(object):
    def __setattr__(self, key, val):
        if key == 'apple' or key == 'orange':
            # Decide what to do about it
        self.__dict__[key] = val

Звярніце ўвагу, што вам неабходна атрымаць доступ да ключа праз аб'екта __ дыктуе __ , каб пазбегнуць бясконцага цыклу, так як __ SetAttr __() замяняе нармальны механізм прызначэння.

Акрамя таго, звярніце ўвагу, што гэта будзе правяраць <�моцны> усе прысваенне гэтых двух зменных, у тым ліку і ва ўласным кодзе. Калі гэта не тое, што вы хочаце, а затым паставіць некаторыя выпрабаванні ў __ __ INIT() , як і іншыя прапанавалі.

0
дададзена

You could override __setattr__() for that class, and have it handle that logic for you. See http://docs.python.org/2/reference/datamodel.html#object.setattr

Нешта накшталт

class FooBar(object):
    def __setattr__(self, key, val):
        if key == 'apple' or key == 'orange':
            # Decide what to do about it
        self.__dict__[key] = val

Звярніце ўвагу, што вам неабходна атрымаць доступ да ключа праз аб'екта __ дыктуе __ , каб пазбегнуць бясконцага цыклу, так як __ SetAttr __() замяняе нармальны механізм прызначэння.

Акрамя таго, звярніце ўвагу, што гэта будзе правяраць <�моцны> усе прысваенне гэтых двух зменных, у тым ліку і ва ўласным кодзе. Калі гэта не тое, што вы хочаце, а затым паставіць некаторыя выпрабаванні ў __ __ INIT() , як і іншыя прапанавалі.

0
дададзена
assert (apple is None) != (orange is None)

Калі змясціць гэты код у метадзе __init__ і ваша папярэдняе ўмова фальшыва, элемент AssertionError будзе адкінутая.

0
дададзена