Установить значение по умолчанию (начальное) для дескриптора - PullRequest
0 голосов
/ 24 января 2020

Предположим, мы получили следующий код:

class NonNegative():
    def __set_name__(self, owner, name):
        self.name = name

    def __get__(self, instance, owner):
        if instance is None:
            return self
        return instance.__dict__[self.name]

    def __set__(self, instance, value):
        instance.__dict__[self.name] = value

class Person:
    fingerCount = NonNegative()
    eyesCount = NonNegative()
    def __init__(self, name):
        self.name = name

p = Person("name")
print(p.fingerCount)    <----- I want a default value printed here, instead of a KeyError
print(p.eyesCount)      <-----                 ------ | | ------

Как мне go назначить значение по умолчанию (начальное) для fingerCount и eyesCount соответственно?

Так что я не нужно сделать:

p = Person("name")
p.fingerCount = 10
p.eyesCount = 2
print(p.fingerCount)  # output: 10   
print(p.eyesCount)    # output: 2

, но вместо этого просто можно сделать:

p = Person("name")
print(p.fingerCount)  # output: 10   
print(p.eyesCount)    # output: 2

Ответы [ 2 ]

1 голос
/ 24 января 2020

Передайте значение по умолчанию методу __init__, который сохраняет его для использования, когда instance.__dict__[self.name] еще не существует.

class NonNegative():
    <b>def __init__(self, v=0):  # You may or may not want a default default value
        self.dflt = v</b>

    def __set_name__(self, owner, name):
        self.name = name

    def __get__(self, instance, owner):
        if instance is None:
            return self
        return instance.__dict__<b>.get(self.name, self.dflt)</b>

    def __set__(self, instance, value):
        instance.__dict__[self.name] = value
class Person:
    fingerCount = NonNegative(10)
    eyesCount = NonNegative(2)
    def __init__(self, name):
        self.name = name

Если хотите, вы можете создать подкласс NonNegative для предоставления прецедента-использования c значения по умолчанию.

class FingerCount(NonNegative):
    def __init__(self, v=10):
        super().__init__(v)


class EyeCount(NonNegative):
    def __init__(self, v=2):
        super().__init__(v)


class Person:
    fingerCount = FingerCount()
    eyecount = EyeCount()


class Cyclops(Person):
    eyecount = EyeCount(1)

Если вы хотите, чтобы начальное значение каждого экземпляра для свойства, инициализировали свойство через его установщик в __init__, как и любой другой атрибут.

class Person:
    fingerCount = NonNegative()
    eyesCount = NonNegative()

    def __init__(self, fcount=10, ecount=2):
        self.fingerCount = fcount
        self.eyesCount = ecount
0 голосов
/ 24 января 2020

для большего количества c жестко закодированное решение

class NonNegative:
    def __set_name__(self, owner, name):
        self.name = name

    def __get__(self, instance, owner):
        if instance is None:
            return self
        if isinstance(instance, Person) and instance.__dict__.get('fingerCount') is None:
            instance.fingerCount = 10
        if isinstance(instance, Person) and instance.__dict__.get('eyesCount') is None:
            instance.eyesCount = 2
        return instance.__dict__[self.name]

    def __set__(self, instance, value):
        instance.__dict__[self.name] = value

class Person:
    fingerCount = NonNegative()
    eyesCount = NonNegative()
    def __init__(self, name):
        self.name = name

p = Person("name")
print(p.fingerCount)
print(p.eyesCount)
# 10
# 2
...