Половина решения, __ набор __ на классе не работает, все еще. Решением является пользовательский класс свойства, реализовывая и свойство и staticmethod
class ClassProperty(object):
def __init__(self, fget, fset):
self.fget = fget
self.fset = fset
def __get__(self, instance, owner):
return self.fget()
def __set__(self, instance, value):
self.fset(value)
class Foo(object):
_bar = 1
def get_bar():
print 'getting'
return Foo._bar
def set_bar(value):
print 'setting'
Foo._bar = value
bar = ClassProperty(get_bar, set_bar)
f = Foo()
#__get__ works
f.bar
Foo.bar
f.bar = 2
Foo.bar = 3 #__set__ does not
Есть много причин, чтобы избежать конфигурации в коде, и я рассмотрю некоторые из них в главе о конфигурации в Мастеринг Perl .
Я подытожил это в своем классе Мастеринг Perl , сказав людям, что первое правило программирования - создавать ситуацию, когда вы выполняете меньше работы, и люди оставляют вас в покое. Когда вы помещаете конфигурацию в код, вы тратите больше времени на решение проблем установки и реагирование на поломки. Если вам не нравятся подобные вещи, дайте людям возможность изменить настройки, не заставляя вас больше работать.
Плохая идея помещать данные конфигурации в скомпилированный код , потому что пользователь не может их легко изменить. Для сценариев, просто убедитесь, что он полностью отделен от остальных, и хорошо документируйте.
Моя основная проблема с настройкой во многих небольших скриптах, которые я пишу, заключается в том, что они часто содержат данные для входа (имя пользователя и пароль или токен) в службу, которую я использую. Затем, когда скрипты становятся больше, я начинаю их версию и хочу загрузить их на github.
Поэтому перед каждым коммитом мне нужно заменить мою конфигурацию на несколько фиктивных значений.
$CONFIG{'user'} = 'username';
$CONFIG{'password'} = '123456';
Также вы должны быть осторожны, чтобы эти значения в какой-то момент не попали в историю ваших коммитов. Это может стать очень раздражающим. Когда вы проделали это один или два раза, вы больше никогда не попытаетесь вставить конфигурацию в код.
Извините за длинный список кодов. Ниже приведен удобный модуль Conf.pm, который я использовал во многих системах и который позволяет указывать разные переменные для разных производственных, промежуточных и сред разработки. Затем я строю свои программы так, чтобы они либо принимали параметры среды в командной строке, либо я сохраняю этот файл вне дерева управления исходным кодом, чтобы никогда не перезаписывать его.
AUTOLOAD предоставляет автоматические методы для поиска переменных.
# Instructions:
# use Conf;
# my $c = Conf->new("production");
# print $c->root_dir;
# print $c->log_dir;
package Conf;
use strict;
our $AUTOLOAD;
my $default_environment = "production";
my @valid_environments = qw(
development
production
);
#######################################################################################
# You might need to change this.
sub set_vars {
my ($self) = @_;
$self->{"access_token"} = 'asdafsifhefh';
if ( $self->env eq "development" ) {
$self->{"root_dir"} = "/Users/patrickcollins/Documents/workspace/SysG_perl";
$self->{"server_base"} = "http://localhost:3000";
}
elsif ($self->env eq "production" ) {
$self->{"root_dir"} = "/mnt/SysG-production/current/lib";
$self->{"server_base"} = "http://api.SysG.com";
$self->{"log_dir"} = "/mnt/SysG-production/current/log"
} else {
die "No environment defined\n";
}
#######################################################################################
# You shouldn't need to configure this.
# More dirs. Move these into the dev/prod sections if they're different per env.
my $r = $self->{'root_dir'};
my $b = $self->{'server_base'};
$self->{"working_dir"} ||= "$r/working";
$self->{"bin_dir"} ||= "$r/bin";
$self->{"log_dir"} ||= "$r/log";
# Other URLs. Move these into the dev/prod sections if they're different per env.
$self->{"new_contract_url"} = "$b/SysG-training-center/v1/contract/new";
$self->{"new_documents_url"} = "$b/SysG-training-center/v1/documents/new";
}
#######################################################################################
# Code, don't change below here.
sub new {
my ($class,$env) = @_;
my $self = {};
bless ($self,$class);
if ($env) {
$self->env($env);
} else {
$self->env($default_environment);
}
$self->set_vars;
return $self;
}
sub AUTOLOAD {
my ($self,$val) = @_;
my $type = ref ($self) || die "$self is not an object";
my $field = $AUTOLOAD;
$field =~ s/.*://;
#print "field: $field\n";
unless (exists $self->{$field} || $field =~ /DESTROY/ )
{
die "ERROR: {$field} does not exist in object/class $type\n";
}
$self->{$field} = $val if ($val);
return $self->{$field};
}
sub env {
my ($self,$in) = @_;
if ($in) {
die ("Invalid environment $in") unless (grep($in,@valid_environments));
$self->{"_env"} = $in;
}
return $self->{"_env"};
}
1;